function new21Game(n, k, maxPts) {
  // 当k为0时，爱丽丝不抽牌，得分为0，所以概率为1（如果0 <= n）
  if (k === 0) return 1.0;

  // 当k > n时，爱丽丝至少要抽到k分，所以不可能不超过n分，概率为0
  if (k > n) return 0.0;

  // dp[i]表示当前得分为i时，最终得分不超过n的概率
  const dp = new Array(n + 1).fill(0);

  // 当i >= k时，停止抽牌
  // 如果i <= n，概率为1；否则为0（数组初始化为0）
  for (let i = k; i <= n; i++) {
    dp[i] = 1.0;
  }

  // 计算初始窗口的和（dp[k]到dp[k + maxPts - 1]的和）
  // 但不能超过n
  let sum = Math.min(n - k + 1, maxPts);

  // 从k-1开始往回计算
  for (let i = k - 1; i >= 0; i--) {
    // 当前概率等于窗口内概率的平均值
    dp[i] = sum / maxPts;

    // 计算即将离开窗口的值
    let remove = 0;
    if (i + maxPts <= n) {
      remove = dp[i + maxPts];
    }

    // 更新滑动窗口的和：加上新进入窗口的dp[i]，减去离开窗口的remove
    sum += dp[i] - remove;
  }

  // 返回初始状态（0分）时的概率
  return dp[0];
}

// 测试示例
console.log(new21Game(10, 1, 10)); // 输出: 1.00000
console.log(new21Game(6, 1, 10)); // 输出: 0.60000
console.log(new21Game(21, 17, 10)); // 输出: 0.73278
